﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using ServiceStack.Text;

namespace StackExchange.Redis
{



    public static class TypedSortedSetExtensionMethods
    {


        public static bool SortedSetAdd<TItem>(this IDatabase database, RedisKey key, TItem item, double score, CommandFlags flags)
        {

            var value = JsonSerializer.SerializeToString(item);
            return database.SortedSetAdd(key, value, score, flags);
        }

        public static Task<bool> SortedSetAddAsync<TItem>(this IDatabase database, RedisKey key, TItem item, double score, CommandFlags flags)
        {
            var value = JsonSerializer.SerializeToString(item);
            return database.SortedSetAddAsync(key, value, score, flags);
        }

        public static long SortedSetAdd<TItem>(this IDatabase database, RedisKey key, SortedSetItem<TItem>[] items, CommandFlags flags)
        {
            if (items == null || items.Length == 0) return 0;
            SortedSetEntry[] values = new SortedSetEntry[items.Length];
            for (int i = 0; i < items.Length; i++)
            {
                values[i] = items[i];
            }
            return database.SortedSetAdd(key, values, flags);
        }


        public static Task<long> SortedSetAddAsync<TItem>(this IDatabase database, RedisKey key, SortedSetItem<TItem>[] items, CommandFlags flags)
        {
            if (items == null || items.Length == 0) return new Task<long>(() => 0);
            SortedSetEntry[] values = new SortedSetEntry[items.Length];
            for (int i = 0; i < items.Length; i++)
            {
                values[i] = items[i];
            }
            return database.SortedSetAddAsync(key, values, flags);
        }

        public static long SortedSetAdd<TItem>(this IDatabase database, RedisKey key, SortedSetItem<TItem>[] items, When when = When.Always, CommandFlags flags = CommandFlags.None)
        {
            if (items == null || items.Length == 0) return 0;
            SortedSetEntry[] values = new SortedSetEntry[items.Length];
            for (int i = 0; i < items.Length; i++)
            {
                values[i] = items[i];
            }
            return database.SortedSetAdd(key, values, when, flags);
        }

        public static Task<long> SortedSetAddAsync<TItem>(this IDatabase database, RedisKey key, SortedSetItem<TItem>[] items, When when = When.Always, CommandFlags flags = CommandFlags.None)
        {
            if (items == null || items.Length == 0) return new Task<long>(() => 0);
            SortedSetEntry[] values = new SortedSetEntry[items.Length];
            for (int i = 0; i < items.Length; i++)
            {
                values[i] = items[i];
            }
            return database.SortedSetAddAsync(key, values, when, flags);
        }

        public static bool SortedSetAdd<TItem>(this IDatabase database, RedisKey key, TItem item, double score, When when = When.Always, CommandFlags flags = CommandFlags.None)
        {
            var value = JsonSerializer.SerializeToString(item);
            return database.SortedSetAdd(key, value, score, when, flags);
        }

        public static Task<bool> SortedSetAddAsync<TItem>(this IDatabase database, RedisKey key, TItem item, double score, When when = When.Always, CommandFlags flags = CommandFlags.None)
        {
            var value = JsonSerializer.SerializeToString(item);
            return database.SortedSetAddAsync(key, value, score, when, flags);
        }


        public static SortedSetItem<TItem>[] SortedSetRangeByRankWithScores<TItem>(this
             IDatabase database, RedisKey key, long start = 0, long stop = -1, Order order = Order.Ascending, CommandFlags flags = CommandFlags.None)
        {
            var values = database.SortedSetRangeByRankWithScores(key, start, stop, order, flags);
            if (values == null) return null;
            if (values.Length == 0) return new SortedSetItem<TItem>[0];
            SortedSetItem<TItem>[] items = new SortedSetItem<TItem>[values.Length];
            for (int i = 0; i < values.Length; i++)
            {
                items[i] = values[i];
            }
            return items;
        }

        public static Task<SortedSetItem<TItem>[]> SortedSetRangeByRankWithScoresAsync<TItem>(this
             IDatabase database, RedisKey key, long start = 0, long stop = -1, Order order = Order.Ascending, CommandFlags flags = CommandFlags.None)
        {
            return database.SortedSetRangeByRankWithScoresAsync(key, start, stop, order, flags).ContinueWith(task =>
            {
                var values = task.Result;
                if (values == null) return null;
                if (values.Length == 0) return new SortedSetItem<TItem>[0];
                SortedSetItem<TItem>[] items = new SortedSetItem<TItem>[values.Length];
                for (int i = 0; i < values.Length; i++)
                {
                    items[i] = values[i];
                }
                return items;

            });
        }


        public static TItem[] SortedSetRangeByScore<TItem>(this IDatabase database, RedisKey key, double start = double.NegativeInfinity, double stop = double.PositiveInfinity, Exclude exclude = Exclude.None, Order order = Order.Ascending, long skip = 0, long take = -1, CommandFlags flags = CommandFlags.None)
        {
            var values = database.SortedSetRangeByScore(key, start, stop, exclude, order, skip, take, flags);
            if (values == null) return null;
            if (values.Length == 0) return new TItem[0];
            TItem[] items = new TItem[values.Length];
            for (int i = 0; i < values.Length; i++)
            {
                items[i] = JsonSerializer.DeserializeFromString<TItem>(values[i]);
            }
            return items;
        }

        public static Task<TItem[]> SortedSetRangeByScoreAsync<TItem>(this IDatabase database, RedisKey key, double start = double.NegativeInfinity, double stop = double.PositiveInfinity, Exclude exclude = Exclude.None, Order order = Order.Ascending, long skip = 0, long take = -1, CommandFlags flags = CommandFlags.None)
        {
            return database.SortedSetRangeByScoreAsync(key, start, stop, exclude, order, skip, take, flags).ContinueWith(task =>
            {
                var values = task.Result;
                if (values == null) return null;
                if (values.Length == 0) return new TItem[0];
                TItem[] items = new TItem[values.Length];
                for (int i = 0; i < values.Length; i++)
                {
                    items[i] = JsonSerializer.DeserializeFromString<TItem>(values[i]);
                }
                return items;
            });
        }


        public static SortedSetItem<TItem>[] SortedSetRangeByScoreWithScores<TItem>(this IDatabase database, RedisKey key, double start = double.NegativeInfinity, double stop = double.PositiveInfinity, Exclude exclude = Exclude.None, Order order = Order.Ascending, long skip = 0, long take = -1, CommandFlags flags = CommandFlags.None)
        {
            var values = database.SortedSetRangeByScoreWithScores(key, start, stop, exclude, order, skip, take, flags);
            if (values == null) return null;
            if (values.Length == 0) return new SortedSetItem<TItem>[0];
            SortedSetItem<TItem>[] items = new SortedSetItem<TItem>[values.Length];
            for (int i = 0; i < values.Length; i++)
            {
                items[i] = values[i];
            }
            return items;
        }

        public static Task<SortedSetItem<TItem>[]> SortedSetRangeByScoreWithScoresAsync<TItem>(this IDatabase database, RedisKey key, double start = double.NegativeInfinity, double stop = double.PositiveInfinity, Exclude exclude = Exclude.None, Order order = Order.Ascending, long skip = 0, long take = -1, CommandFlags flags = CommandFlags.None)
        {
            return database.SortedSetRangeByScoreWithScoresAsync(key, start, stop, exclude, order, skip, take, flags).ContinueWith(task =>
            {
                var values = task.Result;
                if (values == null) return null;
                if (values.Length == 0) return new SortedSetItem<TItem>[0];
                SortedSetItem<TItem>[] items = new SortedSetItem<TItem>[values.Length];
                for (int i = 0; i < values.Length; i++)
                {
                    items[i] = values[i];
                }
                return items;
            });
        }



        public static TItem[] SortedSetRangeByValue<TItem>(this IDatabase database, RedisKey key, TItem min, TItem max, Exclude exclude = Exclude.None, long skip = 0, long take = -1, CommandFlags flags = CommandFlags.None)
        {
            var minValue = JsonSerializer.SerializeToString(min);
            var maxValue = JsonSerializer.SerializeToString(max);
            var values = database.SortedSetRangeByValue(key, minValue, maxValue, exclude, skip, take, flags);
            var items = new TItem[values.Length];
            for (int i = 0; i < values.Length; i++)
            {
                items[i] = JsonSerializer.DeserializeFromString<TItem>(values[i]);
            }
            return items;
        }

        public static Task<TItem[]> SortedSetRangeByValueAsync<TItem>(this IDatabase database, RedisKey key, TItem min, TItem max, Exclude exclude = Exclude.None, long skip = 0, long take = -1, CommandFlags flags = CommandFlags.None)
        {
            var minValue = JsonSerializer.SerializeToString(min);
            var maxValue = JsonSerializer.SerializeToString(max);
            return database.SortedSetRangeByValueAsync(key, minValue, maxValue, exclude, skip, take, flags).ContinueWith(task =>
            {
                var values = task.Result;
                var items = new TItem[values.Length];
                for (int i = 0; i < values.Length; i++)
                {
                    items[i] = JsonSerializer.DeserializeFromString<TItem>(values[i]);
                }
                return items;
            });
        }


        public static long? SortedSetRank<TItem>(this IDatabase database, RedisKey key, TItem item, Order order = Order.Ascending, CommandFlags flags = CommandFlags.None)
        {
            var value = JsonSerializer.SerializeToString(item);
            return database.SortedSetRank(key, value, order, flags);
        }

        public static Task<long?> SortedSetRankAsync<TItem>(this IDatabase database, RedisKey key, TItem item, Order order = Order.Ascending, CommandFlags flags = CommandFlags.None)
        {
            var value = JsonSerializer.SerializeToString(item);
            return database.SortedSetRankAsync(key, value, order, flags);
        }

        public static bool SortedSetRemove<TItem>(this IDatabase database, RedisKey key, TItem item, CommandFlags flags = CommandFlags.None)
        {
            var value = JsonSerializer.SerializeToString(item);
            return database.SortedSetRemove(key, value, flags);
        }

        public static Task<bool> SortedSetRemoveAsync<TItem>(this IDatabase database, RedisKey key, TItem item, CommandFlags flags = CommandFlags.None)
        {
            var value = JsonSerializer.SerializeToString(item);
            return database.SortedSetRemoveAsync(key, value, flags);
        }

        public static long SortedSetRemove<TItem>(this IDatabase database, RedisKey key, TItem[] items, CommandFlags flags = CommandFlags.None)
        {
            if (items == null || items.Length == 0) return 0;
            RedisValue[] values = new RedisValue[items.Length];
            for (int i = 0; i < items.Length; i++)
            {
                values[i] = JsonSerializer.SerializeToString(items[i]);
            }
            return database.SortedSetRemove(key, values, flags);
        }


        public static Task<long> SortedSetRemoveAsync<TItem>(this IDatabase database, RedisKey key, TItem[] items, CommandFlags flags = CommandFlags.None)
        {
            if (items == null || items.Length == 0) return new Task<long>(() => 0);
            RedisValue[] values = new RedisValue[items.Length];
            for (int i = 0; i < items.Length; i++)
            {
                values[i] = JsonSerializer.SerializeToString(items[i]);
            }
            return database.SortedSetRemoveAsync(key, values, flags);
        }
    }
}
